# vim:ts=4:sw=4:noet:
""" Code editor (StyledTextCtrl) """

import wx
import wx.stc
import re

DEFAULT_DOC_FONT_SIZE = 10
DEFAULT_FONT_SIZE = 10

if wx.Platform == '__WXMSW__':
	DEFAULT_FONT_FACE = "Courier New"
	DEFAULT_DOC_FONT_FACE = "Verdana"
elif wx.Platform == '__WXMAC__':
	DEFAULT_FONT_FACE = "Monaco"
	DEFAULT_DOC_FONT_FACE = "Helvetica"
	DEFAULT_FONT_SIZE = 11
	DEFAULT_DOC_FONT_SIZE = 12
else:
	DEFAULT_FONT_FACE = "Monospace"
	DEFAULT_DOC_FONT_FACE = "Bitstream Vera Serif"


class StyleItem:
	def __init__(self, type, fore=None, back=None, bold=None, italic=None, size=None):
		self.type = type
		self.fore = fore
		self.back = back
		self.bold = bold
		self.italic = italic
		self.size = size

	def getSpec(self):
		r = "face:%s," %  DEFAULT_FONT_FACE
		if self.fore:   r += "fore:%s," % self.fore
		if self.back:   r += "back:%s," % self.back
		if self.bold:   r += "bold,"
		if self.italic: r += "italic,"
		if self.size:   r += "size:%d," % self.size
		else:           r += "size:%d," % DEFAULT_FONT_SIZE
		return r[:-1]

class Style:
	def __init__(self):
		self.items = []

	def add(self, i):
		self.items.append(i)

	def apply(self, ed):
		for i in self.items:
			t = getattr(wx.stc, "STC_%s" % i.type.upper())
			ed.StyleSetSpec(t, i.getSpec())

class Editor(wx.stc.StyledTextCtrl):

	def __init__(self, parent, style=wx.SUNKEN_BORDER):
		wx.stc.StyledTextCtrl.__init__(self, parent, -1, wx.DefaultPosition, wx.DefaultSize, style=style)

		self.SetMargins(5,0)
		self.SetViewWhiteSpace(False)
		self.SetEOLMode(wx.stc.STC_EOL_LF)
		self.SetUseAntiAliasing(False) #True)
		self.SetWrapMode(wx.stc.STC_WRAP_WORD)
		self.SetTabWidth(4)

		self.IndicatorSetForeground(0,"#ff0000")
		
		self.MarkerDefine(25, wx.stc.STC_MARK_CHARACTER+ord("!"), "#ff0000", "#ffeeee")
		self.SetMarginWidth(0, 0)	
		self.SetMarginWidth(1, 0)
		self.SetMarginWidth(2, 0)

		self.AutoCompStops("()\s\033'") 
		self.AutoCompSetFillUps("\n\r") 
		self.AutoCompSetIgnoreCase(True) 
		#self.SetMarginType(0, wx.stc.STC_MARGIN_SYMBOL) #margin 2 for symbols
		#self.SetMarginMask(0, wx.stc.STC_MASK_FOLDERS)  #set up mask for folding symbols
		#self.SetMarginSensitive(0, True)           #this one needs to be mouse-aware
							 
		self.SetLexer(wx.stc.STC_LEX_SMALLTALK)
		"""
		self.keywords = ["self", "at:", "do", "ifTrue:", "ifFalse:", 
				"true", "false", "subclass:", "to","nil",
				"class", "new:", "put:"]
		self.SetKeyWords(0," ".join(self.keywords))
				"""

		defF, defS = DEFAULT_FONT_FACE, DEFAULT_FONT_SIZE
		# Global default styles for all languages
		self.StyleSetSpec(wx.stc.STC_STYLE_DEFAULT,	 "face:%s,size:%d" % (defF, defS))
		self.StyleClearAll()  # Reset all to be like the default
		
		# Global default styles for all languages
		self.StyleSetSpec(wx.stc.STC_STYLE_DEFAULT,	 "face:%s,size:%d" % (defF, defS))
		self.StyleSetSpec(wx.stc.STC_STYLE_CONTROLCHAR, "face:%s" % defF)
		self.StyleSetSpec(wx.stc.STC_STYLE_BRACELIGHT,  "fore:#FFFFFF,back:#0000FF,bold")
		self.StyleSetSpec(wx.stc.STC_STYLE_BRACEBAD,	"fore:#000000,back:#FF0000,bold")

		s = Style()
		cNormal =  "#222222"
		cSpecial = "#d0711d"
		cLiteral = "#579dfd"
		cComment = "#0f7300"
		cPunct   = "#777777"

		s.add(StyleItem("st_default",     fore=cNormal))
		s.add(StyleItem("st_comment",     fore=cComment, italic=True))
                                      
		s.add(StyleItem("st_number",      fore=cLiteral))
		s.add(StyleItem("st_string",      fore=cLiteral))
		s.add(StyleItem("st_character",   fore=cLiteral))
		s.add(StyleItem("st_symbol",      fore=cLiteral))
		s.add(StyleItem("st_bool",        fore=cLiteral))
                                      
		s.add(StyleItem("st_kwsend",      fore=cSpecial))
		s.add(StyleItem("st_spec_sel",    fore=cSpecial))
		                                  
		s.add(StyleItem("st_binary",      fore=cPunct))
		s.add(StyleItem("st_return",      fore=cPunct))
		s.add(StyleItem("p_commentblock", fore=cPunct))

		#s.add(StyleItem("st_assign", fore="#ff8822"))
		#s.add(StyleItem("st_global", fore="#00ff00"))
		#s.add(StyleItem("st_nil", fore="#00ff00"))
		#s.add(StyleItem("st_self", fore="#00ff00"))
		#s.add(StyleItem("st_special", fore="#0000ff"))
		#s.add(StyleItem("st_super", fore="#ff00ff"))
	
		s.apply(self)

		self.originalText = ""
		self.acWords = ""
		self.setAutoWords([])

	def disableSyntax(self):
		defF, defS = DEFAULT_DOC_FONT_FACE, DEFAULT_DOC_FONT_SIZE
		self.StyleClearAll()
		self.SetLexer(wx.stc.STC_LEX_NULL)
		self.StyleSetSpec(wx.stc.STC_ST_DEFAULT, "face:%s,size:%d" % (defF, defS))

	def setText(self, text):
		#self.SetScrollWidth(1000)
		if self.GetReadOnly():
			self.SetReadOnly(False)
			self.SetText(text)
			self.SetReadOnly(True)
		else:
			self.SetText(text)
		#maxx = 0
		#for n in range(self.GetLineCount()):
		#	x,y = self.PointFromPosition(self.GetLineEndPosition(n))
		#	if x>maxx:
		#		maxx = x
		#print maxx
		#self.SetScrollWidth(maxx)
		self.originalText = "%s" % text

	def hasChanged(self):
		return self.originalText!=self.GetText()

	def getKeyWordStr(self):
		res = re.findall("[^\(\)\s]+$", self.GetTextRange(
				self.PositionFromLine(self.GetCurrentLine()), 
				self.GetCurrentPos()))
		if res and len(res)==1:
			return res[0]
		else:
			return ""

	def setAutoWords(self, words):
		basewords = ["self", "super", "nil", "true", "false"]
		self.acWords = [w for w in basewords]
		self.acWords.extend(words)
		#print self.acWords

	def getWordList(self, word):
		return ' '.join([w for w in self.acWords if w.find(word)==0])

	def doAutocomplete(self):
		r = self.getKeyWordStr()
		if r=="":
			return
		matches = self.getWordList(r)
		self.AutoCompShow(len(r), matches)

	def errorLine(self, num):
		start = num[2]
		size = num[3]-num[2]
		#print "errorline",num,start,size
		if size<1:
			print "error size negative"
			size = 1
		tl = len(self.GetText())
		if start<0:
			print "error start negative"
			start = 0
		if start>=tl:
			print "error postion beyond text"
			start = tl-2
		self.StartStyling(start, 0x20)
		self.SetStyling(size, 0x20)
		self.MarkerAdd(num[0]-2,25)

	def markLine(self, num):
		self.MarkerDeleteAll(25)
		self.MarkerAdd(num,25)

	def errorClear(self):
		self.StartStyling(0, 0x60)
		self.SetStyling(len(self.GetText()),0x0)
		self.MarkerDeleteAll(25)
		
	def canCopy(self):
		return self.GetSelectionStart() != self.GetSelectionEnd()

	def canCut(self):
		return self.canCopy() and self.canEdit()

	def canEdit(self):
		return not self.GetReadOnly()

	def canPaste(self):
		return wx.stc.StyledTextCtrl.CanPaste(self) and self.canEdit()


